package io.mft.dev.base.cat;

import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.alibaba.druid.filter.FilterAdapter;
import com.alibaba.druid.filter.FilterChain;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.proxy.jdbc.DataSourceProxy;
import com.alibaba.druid.proxy.jdbc.PreparedStatementProxy;
import com.alibaba.druid.proxy.jdbc.ResultSetProxy;
import com.alibaba.druid.proxy.jdbc.StatementProxy;
import com.dianping.cat.Cat;
import com.dianping.cat.message.Message;
import com.dianping.cat.message.Transaction;

import cn.hutool.crypto.digest.MD5;

/**
 * cat监控drui连接池
 * 
 * @说明：TODO
 * @类型名称：DruidCatFilter
 * @创建者: 胡常建
 * @创建时间: 2021年11月1日 上午10:57:34
 * @修改者: 胡常建
 * @修改时间: 2021年11月1日 上午10:57:34
 */
public class CatDruidFilter extends FilterAdapter {

	private String dbType;

	private String url;

	private String transactionType = "SQL";

	
	Map<String, String> sqlMd5Map=new ConcurrentHashMap<>();
	public void setDbType(String dbType) {
		this.dbType = dbType;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	@Override
	public void init(DataSourceProxy dataSource) {
		DruidDataSource druidDataSource = (DruidDataSource) dataSource;
		dbType = druidDataSource.getDriverClassName();
		url = dataSource.getUrl();
	}

	private String sqlMd5(String sql) {
		if (sqlMd5Map.containsKey(sql)) {
			return sqlMd5Map.get(sql);
		}else {
			String md5= MD5.create().digestHex(sql);
			sqlMd5Map.put(sql, md5);
			return md5;
		}
		
	}
	@Override
	public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
		String sqlId=sqlMd5(sql);
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", sql);
		boolean result;
		try {
			result = super.statement_execute(chain, statement, sql);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}
		return result;
	}

	@Override
	public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
			throws SQLException {
		String sqlId=sqlMd5(sql);
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", sql);
		boolean result;
		try {
			result = super.statement_execute(chain, statement, sql, autoGeneratedKeys);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}

		return result;
	}

	@Override
	public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, int[] columnIndexes)
			throws SQLException {
		String sqlId=sqlMd5(sql);
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", sql);
		boolean result;
		try {
			result = super.statement_execute(chain, statement, sql, columnIndexes);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}

		return result;
	}

	@Override
	public boolean statement_execute(FilterChain chain, StatementProxy statement, String sql, String[] columnNames)
			throws SQLException {
		String sqlId=sqlMd5(sql);
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", sql);
		boolean result;
		try {
			result = super.statement_execute(chain, statement, sql, columnNames);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}

		return result;
	}

	@Override
	public int[] statement_executeBatch(FilterChain chain, StatementProxy statement) throws SQLException {
		String sqlId=sqlMd5(statement.getBatchSql());
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", statement.getBatchSql());
		int[] result;
		try {
			result = super.statement_executeBatch(chain, statement);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}

		return result;
	}

	@Override
	public ResultSetProxy statement_executeQuery(FilterChain chain, StatementProxy statement, String sql)
			throws SQLException {
		String sqlId=sqlMd5(sql);
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", sql);
		ResultSetProxy result;
		try {
			result = super.statement_executeQuery(chain, statement, sql);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}

		return result;
	}

	@Override
	public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql) throws SQLException {
		String sqlId=sqlMd5(sql);
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", sql);
		int result;
		try {
			result = super.statement_executeUpdate(chain, statement, sql);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}
		return result;
	}

	@Override
	public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int autoGeneratedKeys)
			throws SQLException {
		String sqlId=sqlMd5(sql);
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", sql);
		int result;
		try {
			result = super.statement_executeUpdate(chain, statement, sql, autoGeneratedKeys);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}
		return result;
	}

	@Override
	public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, int[] columnIndexes)
			throws SQLException {
		String sqlId=sqlMd5(sql);
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", sql);
		int result;
		try {
			result = super.statement_executeUpdate(chain, statement, sql, columnIndexes);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}
		return result;
	}

	@Override
	public int statement_executeUpdate(FilterChain chain, StatementProxy statement, String sql, String[] columnNames)
			throws SQLException {
		String sqlId=sqlMd5(sql);
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", sql);
		int result;
		try {
			result = super.statement_executeUpdate(chain, statement, sql, columnNames);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}
		return result;
	}

	@Override
	public boolean preparedStatement_execute(FilterChain chain, PreparedStatementProxy statement) throws SQLException {
		String sqlId=sqlMd5(statement.getSql());
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", statement.getSql());
		boolean result;
		try {
			result = super.preparedStatement_execute(chain, statement);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}
		return result;
	}

	@Override
	public ResultSetProxy preparedStatement_executeQuery(FilterChain chain, PreparedStatementProxy statement)
			throws SQLException {
		String sqlId=sqlMd5(statement.getSql());
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", statement.getSql());
		ResultSetProxy result;
		try {
			result = super.preparedStatement_executeQuery(chain, statement);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}
		return result;
	}

	@Override
	public int preparedStatement_executeUpdate(FilterChain chain, PreparedStatementProxy statement)
			throws SQLException {
		String sqlId=sqlMd5(statement.getSql());
		Transaction transaction = Cat.newTransaction(transactionType, sqlId);
		CatContext catContext = CatContext.instanceThreadCatContext();
		Cat.logRemoteCallServer(catContext);
		Cat.logEvent("SQL.DbType", dbType);
		Cat.logEvent("SQL.Database", url);
		Cat.logEvent("SQL.sqlId", sqlId);
		Cat.logEvent("SQL.sql", statement.getSql());
		int result;
		try {
			result = super.preparedStatement_executeUpdate(chain, statement);
			transaction.setStatus(Message.SUCCESS);
		} catch (SQLException e) {
			Cat.logError(e);
			transaction.setStatus(e);
			throw e;
		} finally {
			transaction.complete();
		}
		return result;
	}

}
